const redis = require('redis')
const logger = require('../utils/logger')

// Redis配置
const redisConfig = {
  host: process.env.REDIS_HOST || 'localhost',
  port: process.env.REDIS_PORT || 6379,
  password: process.env.REDIS_PASSWORD || undefined,
  db: process.env.REDIS_DB || 0,
  retryDelayOnFailover: 100,
  enableReadyCheck: false,
  maxRetriesPerRequest: null,
  lazyConnect: true
}

// Redis可用性标志
let isRedisAvailable = false
let redisClient = null
let connectionAttempts = 0
const maxConnectionAttempts = 3

// 创建Redis客户端（仅在启用时）
if (process.env.REDIS_ENABLED !== 'false') {
  redisClient = redis.createClient({
    socket: {
      host: redisConfig.host,
      port: redisConfig.port,
      connectTimeout: 5000,
      commandTimeout: 3000
    },
    password: redisConfig.password,
    database: redisConfig.db
  })

  // 错误处理 - 限制错误日志频率
  let lastErrorTime = 0
  redisClient.on('error', (error) => {
    const now = Date.now()
    // 只在5分钟内记录一次错误，避免日志刷屏
    if (now - lastErrorTime > 300000) {
      logger.warn('Redis连接错误，将使用内存缓存替代:', error.message)
      lastErrorTime = now
    }
    isRedisAvailable = false
  })

  redisClient.on('connect', () => {
    logger.info('Redis连接成功')
    isRedisAvailable = true
    connectionAttempts = 0
  })

  redisClient.on('ready', () => {
    logger.info('Redis准备就绪')
    isRedisAvailable = true
  })

  redisClient.on('end', () => {
    logger.info('Redis连接关闭')
    isRedisAvailable = false
  })

  // 尝试连接Redis，失败时不影响应用启动
  const connectRedis = async () => {
    if (connectionAttempts >= maxConnectionAttempts) {
      logger.warn(`Redis连接失败超过${maxConnectionAttempts}次，将禁用Redis缓存功能`)
      return
    }
    
    try {
      connectionAttempts++
      await redisClient.connect()
      isRedisAvailable = true
    } catch (error) {
      logger.warn(`Redis连接失败 (尝试 ${connectionAttempts}/${maxConnectionAttempts}):`, error.message)
      isRedisAvailable = false
      
      // 如果还有重试机会，延迟重试
      if (connectionAttempts < maxConnectionAttempts) {
        setTimeout(connectRedis, 10000) // 10秒后重试
      }
    }
  }

  connectRedis()
} else {
  logger.info('Redis已禁用，将使用内存缓存')
}

// 内存缓存作为Redis的备选方案
const memoryCache = new Map()
const memoryCacheExpiry = new Map()

// 清理过期的内存缓存
setInterval(() => {
  const now = Date.now()
  for (const [key, expiry] of memoryCacheExpiry.entries()) {
    if (expiry && expiry < now) {
      memoryCache.delete(key)
      memoryCacheExpiry.delete(key)
    }
  }
}, 60000) // 每分钟清理一次

// Redis工具方法 - 带内存缓存降级
const redisUtils = {
  // 设置缓存
  async set(key, value, expireSeconds = 3600) {
    try {
      if (isRedisAvailable && redisClient) {
        const serializedValue = JSON.stringify(value)
        if (expireSeconds) {
          await redisClient.setEx(key, expireSeconds, serializedValue)
        } else {
          await redisClient.set(key, serializedValue)
        }
        return true
      } else {
        // 使用内存缓存
        memoryCache.set(key, value)
        if (expireSeconds) {
          memoryCacheExpiry.set(key, Date.now() + expireSeconds * 1000)
        }
        return true
      }
    } catch (error) {
      // Redis失败时降级到内存缓存
      memoryCache.set(key, value)
      if (expireSeconds) {
        memoryCacheExpiry.set(key, Date.now() + expireSeconds * 1000)
      }
      return true
    }
  },

  // 获取缓存
  async get(key) {
    try {
      if (isRedisAvailable && redisClient) {
        const value = await redisClient.get(key)
        return value ? JSON.parse(value) : null
      } else {
        // 使用内存缓存
        const expiry = memoryCacheExpiry.get(key)
        if (expiry && expiry < Date.now()) {
          memoryCache.delete(key)
          memoryCacheExpiry.delete(key)
          return null
        }
        return memoryCache.get(key) || null
      }
    } catch (error) {
      // Redis失败时使用内存缓存
      const expiry = memoryCacheExpiry.get(key)
      if (expiry && expiry < Date.now()) {
        memoryCache.delete(key)
        memoryCacheExpiry.delete(key)
        return null
      }
      return memoryCache.get(key) || null
    }
  },

  // 删除缓存
  async del(key) {
    try {
      if (isRedisAvailable && redisClient) {
        await redisClient.del(key)
      }
      // 同时删除内存缓存
      memoryCache.delete(key)
      memoryCacheExpiry.delete(key)
      return true
    } catch (error) {
      // Redis失败时只删除内存缓存
      memoryCache.delete(key)
      memoryCacheExpiry.delete(key)
      return true
    }
  },

  // 检查键是否存在
  async exists(key) {
    try {
      if (isRedisAvailable && redisClient) {
        const result = await redisClient.exists(key)
        return result === 1
      } else {
        // 使用内存缓存
        const expiry = memoryCacheExpiry.get(key)
        if (expiry && expiry < Date.now()) {
          memoryCache.delete(key)
          memoryCacheExpiry.delete(key)
          return false
        }
        return memoryCache.has(key)
      }
    } catch (error) {
      // Redis失败时使用内存缓存
      const expiry = memoryCacheExpiry.get(key)
      if (expiry && expiry < Date.now()) {
        memoryCache.delete(key)
        memoryCacheExpiry.delete(key)
        return false
      }
      return memoryCache.has(key)
    }
  },

  // 设置过期时间
  async expire(key, seconds) {
    try {
      if (isRedisAvailable && redisClient) {
        await redisClient.expire(key, seconds)
      }
      // 同时设置内存缓存过期时间
      if (memoryCache.has(key)) {
        memoryCacheExpiry.set(key, Date.now() + seconds * 1000)
      }
      return true
    } catch (error) {
      // Redis失败时只设置内存缓存过期时间
      if (memoryCache.has(key)) {
        memoryCacheExpiry.set(key, Date.now() + seconds * 1000)
      }
      return true
    }
  },

  // 获取剩余过期时间
  async ttl(key) {
    try {
      if (isRedisAvailable && redisClient) {
        return await redisClient.ttl(key)
      } else {
        // 使用内存缓存
        const expiry = memoryCacheExpiry.get(key)
        if (!expiry) return -1
        const remaining = Math.floor((expiry - Date.now()) / 1000)
        return remaining > 0 ? remaining : -2
      }
    } catch (error) {
      // Redis失败时使用内存缓存
      const expiry = memoryCacheExpiry.get(key)
      if (!expiry) return -1
      const remaining = Math.floor((expiry - Date.now()) / 1000)
      return remaining > 0 ? remaining : -2
    }
  },

  // 原子递增
  async incr(key) {
    try {
      if (isRedisAvailable && redisClient) {
        return await redisClient.incr(key)
      } else {
        // 使用内存缓存模拟
        const current = memoryCache.get(key) || 0
        const newValue = parseInt(current) + 1
        memoryCache.set(key, newValue)
        return newValue
      }
    } catch (error) {
      // Redis失败时使用内存缓存
      const current = memoryCache.get(key) || 0
      const newValue = parseInt(current) + 1
      memoryCache.set(key, newValue)
      return newValue
    }
  },

  // 原子递减
  async decr(key) {
    try {
      if (isRedisAvailable && redisClient) {
        return await redisClient.decr(key)
      } else {
        // 使用内存缓存模拟
        const current = memoryCache.get(key) || 0
        const newValue = parseInt(current) - 1
        memoryCache.set(key, newValue)
        return newValue
      }
    } catch (error) {
      // Redis失败时使用内存缓存
      const current = memoryCache.get(key) || 0
      const newValue = parseInt(current) - 1
      memoryCache.set(key, newValue)
      return newValue
    }
  },

  // 哈希设置
  async hset(key, field, value) {
    try {
      if (isRedisAvailable && redisClient) {
        await redisClient.hSet(key, field, JSON.stringify(value))
        return true
      } else {
        // 使用内存缓存模拟
        let hash = memoryCache.get(key) || {}
        hash[field] = value
        memoryCache.set(key, hash)
        return true
      }
    } catch (error) {
      // Redis失败时使用内存缓存
      let hash = memoryCache.get(key) || {}
      hash[field] = value
      memoryCache.set(key, hash)
      return true
    }
  },

  // 哈希获取
  async hget(key, field) {
    try {
      if (isRedisAvailable && redisClient) {
        const value = await redisClient.hGet(key, field)
        return value ? JSON.parse(value) : null
      } else {
        // 使用内存缓存
        const hash = memoryCache.get(key)
        return hash && hash[field] ? hash[field] : null
      }
    } catch (error) {
      // Redis失败时使用内存缓存
      const hash = memoryCache.get(key)
      return hash && hash[field] ? hash[field] : null
    }
  },

  // 哈希删除
  async hdel(key, field) {
    try {
      if (isRedisAvailable && redisClient) {
        await redisClient.hDel(key, field)
      }
      // 同时删除内存缓存
      const hash = memoryCache.get(key)
      if (hash && hash[field]) {
        delete hash[field]
        memoryCache.set(key, hash)
      }
      return true
    } catch (error) {
      // Redis失败时只删除内存缓存
      const hash = memoryCache.get(key)
      if (hash && hash[field]) {
        delete hash[field]
        memoryCache.set(key, hash)
      }
      return true
    }
  },

  // 列表推入
  async lpush(key, value) {
    try {
      if (isRedisAvailable && redisClient) {
        await redisClient.lPush(key, JSON.stringify(value))
        return true
      } else {
        // 使用内存缓存模拟
        let list = memoryCache.get(key) || []
        list.unshift(value)
        memoryCache.set(key, list)
        return true
      }
    } catch (error) {
      // Redis失败时使用内存缓存
      let list = memoryCache.get(key) || []
      list.unshift(value)
      memoryCache.set(key, list)
      return true
    }
  },

  // 列表弹出
  async lpop(key) {
    try {
      if (isRedisAvailable && redisClient) {
        const value = await redisClient.lPop(key)
        return value ? JSON.parse(value) : null
      } else {
        // 使用内存缓存模拟
        let list = memoryCache.get(key) || []
        const value = list.shift()
        memoryCache.set(key, list)
        return value || null
      }
    } catch (error) {
      // Redis失败时使用内存缓存
      let list = memoryCache.get(key) || []
      const value = list.shift()
      memoryCache.set(key, list)
      return value || null
    }
  },

  // 获取Redis连接状态
  isConnected() {
    return isRedisAvailable
  },

  // 获取缓存统计信息
  getCacheStats() {
    return {
      redisAvailable: isRedisAvailable,
      memoryCacheSize: memoryCache.size,
      memoryCacheKeys: Array.from(memoryCache.keys())
    }
  }
}

module.exports = redisClient
module.exports.redisUtils = redisUtils
module.exports.isRedisAvailable = () => isRedisAvailable